package com.it.reggie.Controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.it.reggie.Service.CategoryService;
import com.it.reggie.Service.SetmealDishService;
import com.it.reggie.Service.SetmealService;
import com.it.reggie.common.R;
import com.it.reggie.dto.SetmealDto;
import com.it.reggie.entity.Category;
import com.it.reggie.entity.Setmeal;
import com.it.reggie.entity.SetmealDish;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j //日志
@RestController //rest风格开发
@RequestMapping("/setmeal")
public class SetmealController {

    @Autowired
    private SetmealService setmealService;

    @Autowired
    private SetmealDishService setmealDishService;

    @Autowired
    private CategoryService categoryService;

    /**
     * 增加套餐
     * @param setmealDto
     * @return
     */
    @PostMapping
    public R save(@RequestBody SetmealDto setmealDto){
        log.info("SetmealDto {}",setmealDto);
        setmealService.sevaWithDish(setmealDto);
        return R.success("保存成功");
    }


    @GetMapping("/page")
    public R Paging(int page, int pageSize, String name){
        /**
         * 构造分页构造器
         */
        Page<Setmeal> page1 = new Page(page,pageSize);

        /**
         * 条件构造器
         */
        LambdaQueryWrapper<Setmeal> LambdaQueryWrapper = new LambdaQueryWrapper<>();
        LambdaQueryWrapper.like(StringUtils.isNotEmpty(name),Setmeal::getName,name);

        //添加排序条件
        LambdaQueryWrapper.orderByAsc(Setmeal::getUpdateTime);

        setmealService.page(page1,LambdaQueryWrapper);


        // 1、构建一个DTO分页构造器
        Page<SetmealDto> SetmealDtoPage = new Page<>();
        // 我们这里再构造一个分页查询构造器，注意：这个分页查询构造器是查询不出来数据的，因为new Page<>()
        // 后面并没有传入页码和页码对应的展示数量数，也就是说这个分页构造器里面什么都没有，相当于一个空壳

        /**
         * 所有的DishDto 可以理解为 SetmealDto
         *   首先我们要知道，DishDto实体类是Dish实体类的他哥，
         *   （因为DishDto继承了Dish实体类，所以DishDto实体类当中有了Dish实体类的属性包括DishDto实体类中自己的categoryName属性）
         *
         *  我们如果想 让 前端拿到categoryName对应的数据，就需要把数据封装到DishDto实体类的属性当中然后响应给前端相对应的数据，那么前端就可以拿到所有的数据进行展示了。
         *
         *      思路：
         *          我们知道IPage<Dish> page1 = new Page<>(page,pageSize); 这个分页构造器已经拿到了除了前端想要的categoryName除外的所有数据了，
         *          因此我们就可以用拷贝源的方式，我们知道page1分页构造器已经拿到了基本的数据了，那么就肯定拿到了dish数据库中的对应着菜品分类数据的id了，
         *          因此我们就可以把page1分页查询出来的数据和菜品分类对应的id查询出来的菜品分类数据拷贝到dishDtoPage的分页查询构造器当中（因为这个构造器相当于一个空壳）
         *          现在我们把数据都拷贝过去了，那么前端就能拿到原始的除categoryName的所有数据和categoryName对应的分类管理数据了。
         */

        // 所有的DishDto 可以理解为 SetmealDto
        // 2、把page1分页查询构造器的属性copy到dishDtoPage分页查询构造器中（这时的dishDtoPage还是一个空壳呢）
        BeanUtils.copyProperties(page1,SetmealDtoPage,"records");   // 这里就是把page1的属性先拷贝到dishDtoPage构造器
        // 这里我们知道page1构造器中已经有分页查询出来的数据了，并且数据protected List<T> records;;已经封装在records集合当中了，（点击page1的Page查看源码）
        // 因此我们这里拷贝的时候后面加上了“records”的目的就是不拷贝page1构造器中分页查询出来的数据，其他的属性都先拷贝上，就相当于先克隆个page1的壳子

        // 3、既然page1构造器已经拿到了除了前端想要的categoryName除外的所有数据了，那么我们就把page1分页查询出来封装在List<OrderItem> orders()集合中的数据先获取出来
        // 也就是说先把page1分页查询出来的数据拿出来，我们需要用category_id字段获取那个有菜品分类的name数据
        List<Setmeal> records = page1.getRecords();    // 把page1分页查询出来的数据获取出来了，
        // （我们知道该List集合当中储存的就是分页查询出来的那些数据一个一个
        //  封装在Dish实体类属性当中以Dish对象的形式封装在List集合当中【就是页面展示出来的那些数据，
        //  其实底层是分页查询出来的数据是以一条一条封装在实体类属性当中然后封装在集合当中的】）

        // 4、因此我们就可以遍历该List集合，把page1分页查询出来的Dish实体类中的categoryId属性数据获取出来（
        // 该实体类的categoryId对应dish数据库中的category_id字段）
        // 我们又知道该dish数据库中的category_id字段对应着category数据库中的id字段，
        // 该category数据库中就有前端想要的菜品分类数据（也就是category数据库中的name字段数据）
        // 因此知道这个关系后，我们就可以通过获取Dish实体类当中的categoryId属性数据传给category数据库对应的数据层，
        // 然后通过id的形式把category数据库中的菜品分类数据查询出来了。
        // 注意：这里的遍历用的是stream流的方式遍历的（增强for也是可以的，我是写不出来了操）

        // 因此我们这里就相当于遍历records， 遍历List集合中封装了分页查询出来的封装在Dish属性中数据的Dish对象 （
        // 把封装了分页查询数据的Dish对象一个一个遍历出来）
        List<SetmealDto> list = records.stream().map((item) ->{    // 这相当于增强for循环

            Long categoryId = item.getCategoryId();// 然后一个一个获取其records集合中封装在Dish实体类的categoryId属性中的数据了
            // 5、调用有菜品分类数据的category数据库的数据层，然后把上面获取到的categoryId数据与category数据库的id相比较，然后拿到category数据库中的name字段数据（也就是菜品分类数据）
            // Category category = categoryService.getById(categoryId);    // 因此我们就可以让category数据库对应的数据层调用通过id查询数据的方法功能
            Category category = categoryService.getById(categoryId);    // 因此我们就可以让category数据库对应的数据层调用通过id查询数据的方法功能

            /**
             *  我们这里需要进行判断一下，因为有可能category数据库中通过我们传递的categoryId进行id查询的时候，可能会查询不到数据，
             *  如果不判断的话，就会出现BUG,判断查询出来的数据不为null的时候，再进行获取该Category实体类对应的数据库中的name字段数据
             */
            // 7、获取了category数据库中的name字段：代表的就是菜品分类数据后，就直接封装到DishDto实体类的categoryName属性当中即可，
            SetmealDto setmealDto = new SetmealDto();    // 把DTO实体类对象new出来，供下面封装数据

            if (category != null){
                // 6、上面拿到了category数据库中的数据之后
                // （我们知道category数据库通过categoryId查询出来的数据是封装到在Category对象属性中的），
                //  因此我们这里就可以获取Category实体类中的name属性（相当于category数据库中的name字段：
                //  代表的就是菜品分类）来获取菜品分类的数据了。
                String name1 = category.getName();

                setmealDto.setCategoryName(name1); // 获取的name菜品分类数据封装到DTO实体类的属性当中
            }

            // 如果对应的id查询的category数据为null的话，就还是返回page1分页查询出来的数据而已

            // 8、到了这里我们就知道，DTO实体类的菜品分类数据已经成功封装到了categoryName属性当中了。
            // 此时DTO对应的分页查询构造器中我们知道只有categoryName属性的数据，
            // 因此我们也要通过拷贝的方式，把page1分页查询出来的数据封装到DTO实体类当中
            // （因为DTO实体类继承了Dish，因此现在DTO实体类属性中只有categoryName属性有数据，
            // 因此我们把page1分页查询出来的封装在records集合中的数据一个一个封装到DTO实体类当中）
            // 做法： 就是我们知道现在我们遍历的就是page1分页查询封装在records集合中的数据，
            // 因此我们可以在遍历的过程中，把records集合中的数据一个一个拷贝封装到DTO的属性当中，然后存入到集合中
            BeanUtils.copyProperties(item,setmealDto); // item就是遍历出来的一个一个的page1分页查询封装在records集合中
                                                    // 的数据对象（Dish对象，分页查询的每条数据都以封装在Dish对象属性
                                                    //  当中封装到集合中），然后直接把这一个一个的数据拷贝封装到DTO实体类属性中


            return setmealDto;
            // 到了这一步后，我们就知道dishDto实体类categoryName属性当中已经封装到了菜品分类数据了
            // （ dishDto.setCategoryName(name1);），并且也把page1分页查询的数据依次封装到了dishDto实体类
            // 属性当中了（也就是说继承的Dish实体类的属性，BeanUtils.copyProperties(item,dishDto)），
            // 然后依次循环返回给list集合当中。

            // return dishDto; 也可以说把DishDto dishDto = new DishDto(); 当这个dishDto对象通过下面的dishDto.setCategoryName(name1);和
            // 拷贝： BeanUtils.copyProperties(item,dishDto); 把category_name 分类菜品数据和其他的page1分页查询出来的数据封装到该对象的属性当中后，
            // 就返回这个dishDto对象到list集合当中（List<DishDto> list ），最终通过依次循环，把该对象属性中封装的数据全部封装到了list集合当中了，最后再把
            // 这些数据dishDtoPage.setRecords(list); 给dishDtoPage分页查询的records集合当中响应给前端即可了，前端就都能获取到了。

        }).collect(Collectors.toList());



        SetmealDtoPage.setRecords(list);   // 最终再把list集合中封装的DishDto实体类（该实体类属性中封装完成了前端所要的全部数据），设置到dishDtoPage分页查询
        // 所对应的查询出来封装在records储存的records集合当中，那么就相当于dishDtoPage分页查询出来了所有前端想要的数据了。


        return R.success(SetmealDtoPage);  // 因此这里再把分页查询储存在records集合当中的前端想要的数据响应给前端即可。
    }

    @DeleteMapping
    public R delete(@RequestParam List<Long> ids){
        log.info("id {}",ids);
        setmealService.delete(ids);
        return R.success("商品删除成功");
    }

    @PostMapping("setmeal/{state}/{ids}")
    public R state(int state,List<Long> ids){
        log.info("state {} ids {}",state,ids);

        return null;
    }

    @GetMapping("/list")
    public R<List<Setmeal>>categoryId(Setmeal service){
        log.info("id {}",service);
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(service.getCategoryId()!=null,Setmeal::getCategoryId,service.getCategoryId());
        queryWrapper.eq(service.getStatus()!=null,Setmeal::getStatus,service.getStatus());

        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        List<Setmeal> list = setmealService.list(queryWrapper);
        return R.success(list);
    }

}
